package registry

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"sync"
	"time"

	"gitee.com/yuwenlwl/comsdk/security"
)

// ComponentInfo 组件信息
type ComponentInfo struct {
	AppID          string            // 组件ID，使用app_id与API文档一致
	Name           string            // 组件名称
	Description    string            // 组件描述
	Version        string            // 组件版本
	Endpoints      map[string]string // 组件端点映射
	ServiceURL     string            // 服务URL（必填）
	HealthCheckURL string            // 健康检查URL
}

// RegisterRequest 注册请求
type RegisterRequest struct {
	AppID          string `json:"app_id"`                     // 组件ID（必填）
	ServiceURL     string `json:"service_url"`                // 服务地址（必填）
	HealthCheckURL string `json:"health_check_url,omitempty"` // 健康检查地址（可选）
	Version        string `json:"version,omitempty"`          // 版本号（可选）
}

// APIResponse 接口响应结构
type APIResponse struct {
	Success bool        `json:"success"`
	Message string      `json:"message,omitempty"`
	AppID   string      `json:"app_id,omitempty"`
	Data    interface{} `json:"data,omitempty"`
}

// RegisteredComponent 已注册组件的详细信息
type RegisteredComponent struct {
	ID             int       `json:"id"`
	AppID          string    `json:"app_id"`
	Name           string    `json:"name"`
	Version        string    `json:"version"`
	ServiceURL     string    `json:"service_url"`
	HealthCheckURL string    `json:"health_check_url"`
	Status         string    `json:"status"`
	RegisterTime   time.Time `json:"register_time"`
	LastHeartbeat  time.Time `json:"last_heartbeat"`
	UpdateTime     time.Time `json:"update_time"`
}

// RegistrationStatus 注册状态
type RegistrationStatus struct {
	Registered    bool      // 是否已注册
	LastHeartbeat time.Time // 上次心跳时间
	NextRetryTime time.Time // 下次重试时间
	RetryCount    int       // 重试次数
	GatewayURL    string    // 网关URL
	Error         error     // 最后一次错误
}

// Registrar 注册器接口
type Registrar interface {
	// Register 注册服务组件到API网关
	Register() error

	// Deregister 从API网关注销服务组件
	Deregister() error

	// GetRegisteredComponents 获取已注册的组件列表
	GetRegisteredComponents() ([]RegisteredComponent, error)

	// StartHeartbeat 启动心跳服务
	StartHeartbeat(ctx context.Context, interval time.Duration)

	// GetStatus 获取当前注册状态
	GetStatus() RegistrationStatus
}

// DefaultRegistrar 默认注册器实现
type DefaultRegistrar struct {
	ComponentInfo ComponentInfo
	GatewayURL    string
	RegisterPath  string
	Verifier      security.Verifier // 使用security包的Verifier接口

	mu     sync.RWMutex
	status RegistrationStatus
	client *http.Client
}

// NewRegistrar 创建注册器实例
func NewRegistrar(info ComponentInfo, gatewayURL, registerPath string, verifier security.Verifier) Registrar {
	return &DefaultRegistrar{
		ComponentInfo: info,
		GatewayURL:    gatewayURL,
		RegisterPath:  registerPath,
		Verifier:      verifier,
		client:        &http.Client{Timeout: 10 * time.Second},
		status: RegistrationStatus{
			Registered: false,
			GatewayURL: gatewayURL,
		},
	}
}

// Register 注册服务组件到API网关
func (r *DefaultRegistrar) Register() error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// 如果已经注册成功，直接返回
	if r.status.Registered {
		return nil
	}

	// 构建注册URL
	registerURL := r.GatewayURL + r.RegisterPath

	// 构建请求体 - 严格按照接口文档格式
	reqBody := RegisterRequest{
		AppID:          r.ComponentInfo.AppID,
		ServiceURL:     r.ComponentInfo.ServiceURL,     // 必填字段
		HealthCheckURL: r.ComponentInfo.HealthCheckURL, // 健康检查URL
		Version:        r.ComponentInfo.Version,        // 版本号
	}

	// 确保必填字段有值
	if reqBody.ServiceURL == "" {
		r.setError(fmt.Errorf("缺少必填字段service_url"))
		return fmt.Errorf("缺少必填字段service_url")
	}

	reqBodyBytes, err := json.Marshal(reqBody)
	if err != nil {
		r.setError(err)
		return fmt.Errorf("序列化组件信息失败: %w", err)
	}

	// 创建HTTP请求
	req, err := http.NewRequest("POST", registerURL, bytes.NewBuffer(reqBodyBytes))
	if err != nil {
		r.setError(err)
		return fmt.Errorf("创建注册请求失败: %w", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")

	// 签名请求
	if err := r.Verifier.SignComponentRequest(req); err != nil {
		r.setError(err)
		return fmt.Errorf("签名注册请求失败: %w", err)
	}

	// 发送请求
	resp, err := r.client.Do(req)
	if err != nil {
		r.scheduleRetry()
		r.setError(err)
		return fmt.Errorf("发送注册请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 解析响应
	var response APIResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		r.setError(fmt.Errorf("解析响应失败: %w", err))
		r.scheduleRetry()
		return fmt.Errorf("解析响应失败: %w", err)
	}

	// 检查响应
	if resp.StatusCode != http.StatusOK || !response.Success {
		errMsg := fmt.Sprintf("注册失败，状态码: %d, 错误: %s", resp.StatusCode, response.Message)
		err = fmt.Errorf(errMsg)
		r.scheduleRetry()
		r.setError(err)
		return err
	}

	// 更新状态
	r.status.Registered = true
	r.status.LastHeartbeat = time.Now()
	r.status.RetryCount = 0
	r.status.Error = nil

	return nil
}

// Deregister 从API网关注销服务组件
func (r *DefaultRegistrar) Deregister() error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// 如果未注册，不需要注销
	if !r.status.Registered {
		return nil
	}

	// 构建注销URL - 使用AppID
	deregisterURL := fmt.Sprintf("%s%s/%s", r.GatewayURL, r.RegisterPath, r.ComponentInfo.AppID)

	// 创建HTTP请求
	req, err := http.NewRequest("DELETE", deregisterURL, nil)
	if err != nil {
		r.setError(err)
		return fmt.Errorf("创建注销请求失败: %w", err)
	}

	// 签名请求
	if err := r.Verifier.SignComponentRequest(req); err != nil {
		r.setError(err)
		return fmt.Errorf("签名注销请求失败: %w", err)
	}

	// 发送请求
	resp, err := r.client.Do(req)
	if err != nil {
		r.setError(err)
		return fmt.Errorf("发送注销请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 解析响应
	var response APIResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		r.setError(fmt.Errorf("解析响应失败: %w", err))
		return fmt.Errorf("解析响应失败: %w", err)
	}

	// 检查响应
	if resp.StatusCode != http.StatusOK || !response.Success {
		errMsg := fmt.Sprintf("注销失败，状态码: %d, 错误: %s", resp.StatusCode, response.Message)
		err = fmt.Errorf(errMsg)
		r.setError(err)
		return err
	}

	// 更新状态
	r.status.Registered = false

	return nil
}

// GetRegisteredComponents 获取已注册的组件列表
func (r *DefaultRegistrar) GetRegisteredComponents() ([]RegisteredComponent, error) {
	// 构建查询URL
	listURL := fmt.Sprintf("%s/api/v1/registry/components", r.GatewayURL)

	// 创建HTTP请求
	req, err := http.NewRequest("GET", listURL, nil)
	if err != nil {
		return nil, fmt.Errorf("创建查询请求失败: %w", err)
	}

	// 签名请求
	if err := r.Verifier.SignComponentRequest(req); err != nil {
		return nil, fmt.Errorf("签名查询请求失败: %w", err)
	}

	// 发送请求
	resp, err := r.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送查询请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 解析响应
	var response struct {
		Success bool                  `json:"success"`
		Data    []RegisteredComponent `json:"data"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return nil, fmt.Errorf("解析组件列表失败: %w", err)
	}

	if !response.Success {
		return nil, fmt.Errorf("查询失败")
	}

	return response.Data, nil
}

// StartHeartbeat 启动心跳服务
func (r *DefaultRegistrar) StartHeartbeat(ctx context.Context, interval time.Duration) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	// 立即进行第一次注册尝试
	if err := r.Register(); err != nil {
		fmt.Printf("初始注册失败: %v，将按计划重试\n", err)
	}

	for {
		select {
		case <-ctx.Done():
			// 收到取消信号，停止心跳
			r.Deregister()
			return

		case <-ticker.C:
			r.mu.RLock()
			shouldRegister := !r.status.Registered || time.Since(r.status.LastHeartbeat) > interval
			shouldRetry := !r.status.Registered && time.Now().After(r.status.NextRetryTime)
			r.mu.RUnlock()

			if shouldRegister || shouldRetry {
				if err := r.Register(); err != nil {
					fmt.Printf("心跳注册失败: %v\n", err)
				} else {
					fmt.Println("心跳注册成功")
				}
			}
		}
	}
}

// GetStatus 获取当前注册状态
func (r *DefaultRegistrar) GetStatus() RegistrationStatus {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.status
}

// 内部辅助方法

// setError 设置错误并更新状态
func (r *DefaultRegistrar) setError(err error) {
	r.status.Error = err
}

// scheduleRetry 计算下次重试时间，使用指数退避算法
func (r *DefaultRegistrar) scheduleRetry() {
	r.status.RetryCount++

	// 计算退避时间，基数为1秒，最大为1分钟
	backoffSeconds := math.Min(math.Pow(2, float64(r.status.RetryCount-1)), 60)
	backoffDuration := time.Duration(backoffSeconds) * time.Second

	r.status.NextRetryTime = time.Now().Add(backoffDuration)
}
